#pragma once
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/epoll.h>
#include <errno.h>
#include <signal.h>
#include <time.h>
#include <sys/wait.h>

static int sig_pipefd[2];

class util
{
public:
    //添加事件
    static void addEvent(int epfd, int sock)
    {
        struct epoll_event event;
        event.data.fd = sock;
        event.events = EPOLLIN | EPOLLET;
        assert(epoll_ctl(epfd, EPOLL_CTL_ADD, sock, &event) != -1);
        setNonBlock(sock);
    }
    
    //移除事件
    static void removeEvent(int epfd, int sock)
    {
        assert(epoll_ctl(epfd, EPOLL_CTL_DEL, sock, NULL) != -1);
        close(sock);
    }

    //信号处理函数
    static void sig_handler(int sig)
    {
        int err = errno;
        int msg = 0;
        send(sig_pipefd[1], (char*)&msg, sizeof(msg), 0);
        errno = err;
    }

    //添加信号
    static void addSig(int sig, void (*handler)(int), bool restart = true)
    {
        struct sigaction act;
        memset(&act, 0, sizeof(act));
        act.sa_handler = handler;
        if (restart)
            act.sa_flags |= SA_RESTART;
        sigfillset(&act.sa_mask);
        assert(sigaction(sig, &act, NULL) != -1);
    }

    //设置非阻塞
    static int setNonBlock(int fd)
    {
        int old_op = fcntl(fd, F_GETFL);
        fcntl(fd, F_SETFL, old_op | O_NONBLOCK);
        return old_op;
    }
};

struct process
{
    //进程PID
    pid_t pid;
    //父子进程通信的管道
    int pipefd[2];

    process() : pid(-1)
    {}
};

template <class T>
class processPool
{
public:
    static processPool<T>* create(int listen_fd, int pcess_num = 8)
    {
        if (inst == nullptr)
        {
            inst = new processPool<T>(pcess_num, listen_fd);
        }
        return inst;
    }

    //运行
    void run()
    {
        if (idx != -1)
        {
            run_child();
            return;
        }
        run_parent();
    }

    //析构函数
    ~processPool()
    {
        delete[] sub_process;
    }
private:
    //构造函数
    processPool<T>(int pcess_num, int listen_fd) : listen_sock(listen_fd), process_num(pcess_num), idx(-1), stop(false)
    {
        //子进程数量必须在规定范围内
        assert(process_num > 0 && process_num <= MAX_PROCESS_NUMBER);
        //创建子进程描述数组
        sub_process = new process[process_num];
        assert(sub_process);
        for (int i = 0;i < process_num;i++)
        {
            //创建父子进程通信的管道
            int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sub_process[i].pipefd);
            assert(ret != -1);
            ret = fork();
            if (ret < 0)
            {
                printf("子进程创建失败\n");
                delete[] sub_process;
                exit(-1);
            }
            //子进程
            else if (ret == 0)
            {
                close(sub_process[i].pipefd[0]);
                idx = i;
                break;
            }
            //父进程
            else
            {
                close(sub_process[i].pipefd[1]);
                sub_process[i].pid = ret;
            }
        }
    }

    //父进程运行
    void run_parent()
    {
        sig_setup();

        //创建事件数组
        struct epoll_event events[MAX_EVENT_NUMBER];
        //添加监听事件
        util::addEvent(epfd, listen_sock);
        int sub_process_counter = 0;
        int new_conn = 1;
        //业务逻辑
        while (!stop)
        {
            int n = epoll_wait(epfd, events, MAX_EVENT_NUMBER, -1);
            if (n < 0 && errno != EINTR)
            {
                printf("epoll_wait failed\n");
                break;
            }
            for (int i = 0;i < n;i++)
            {
                int confd = events[i].data.fd;
                //有新的连接到来
                if (confd == listen_sock && (events[i].events & EPOLLIN))
                {
                    int i = sub_process_counter;
                    do
                    {
                        if (sub_process[i].pid != -1)
                            break;
                        i = (i + 1) % process_num;
                    } while (i != sub_process_counter);
                    
                    if (sub_process[i].pid == -1)
                    {
                        stop = true;
                        break;
                    }
                    sub_process_counter = (i + 1) % process_num;
                    // 将文件描述符发送给子进程
                    send(sub_process[i].pipefd[0], (char*)&new_conn, sizeof(new_conn), 0);
                    printf("send to %d child\n", i);
                }
                //处理信号事件
                else if (confd == sig_pipefd[0] && (events[i].events & EPOLLIN))
                {
                    char signals[1024];
                    memset(signals, '\0', sizeof(signals));
                    int ret = recv(confd, signals, sizeof(signals), 0);
                    if (ret > 0)
                    {
                        for (int j = 0;j < ret;j++)
                        {
                            switch (signals[j])
                            {
                            case SIGCHLD:
                                pid_t pid;
                                while ((pid = waitpid(-1, NULL, WNOHANG)) > 0)
                                {
                                    for (int k = 0;k < process_num;k++)
                                    {
                                        if (sub_process[k].pid == pid)
                                        {
                                            printf("%d child join\n", k);
                                            sub_process[k].pid = -1;
                                            close(sub_process[k].pipefd[0]);
                                            break;
                                        }
                                    }
                                }
                                //所有子进程都退出了，则父进程也退出
                                stop = true;
                                for (int k = 0;k < process_num;k++)
                                {
                                    if (sub_process[k].pid != -1)
                                        stop = false;
                                }   
                                break;
                            case SIGINT:
                            case SIGTERM:
                                printf("kill all child process\n");
                                for (int k = 0;k < process_num;j++)
                                {
                                    pid_t pid = sub_process[k].pid;
                                    if (pid == -1)
                                        continue;
                                    kill(pid, SIGTERM);
                                }
                                stop = true;
                                break;
                            default:
                                break;
                            }
                        }
                    }
                    else
                       continue;
                }
                else
                    continue;
            }
        }
        // close(listen_sock);由创建者关闭这个文件描述符
        close(epfd);
    }

    //子进程运行
    void run_child()
    {
        sig_setup();

        int pefd = sub_process[idx].pipefd[1];
        util::addEvent(epfd, pefd);

        struct epoll_event events[MAX_EVENT_NUMBER];
        //创建用户连接数组
        T* users = new T[USER_PER_PROCESS];
        assert(users);
        while (!stop)
        {
            int n = epoll_wait(epfd, events, MAX_EVENT_NUMBER, -1);
            if (n < 0 && errno != EINTR)
            {
                printf("epoll_wait failed child\n");
                break;
            }
            for (int i = 0;i < n;i++)
            {
                int confd = events[i].data.fd;
                //父进程发来数据
                if (confd == pefd && (events[i].events & EPOLLIN))
                {   
                    printf("parent process# 有新的连接到来了\n");
                    int recv_fd = 0;
                    int ret = recv(confd, (char*)&recv_fd, sizeof(recv_fd), 0);
                    if (ret > 0)
                    {
                        struct sockaddr_in client;
                        socklen_t len = sizeof(client);
                        int sock = accept(listen_sock, (struct sockaddr*)&client, &len);
                        if (sock < 0)
                        {
                            printf("child accept failed %d\n", errno);
                            continue;
                        }
                        util::addEvent(epfd, sock);
                        users[sock].init(epfd, sock, client);
                    }
                    else if (ret == 0)
                    {
                        continue;
                    }
                    else
                    {
                        if (errno != EAGAIN)
                        {
                            continue;
                        }
                    }
                }
                //处理信号事件
                else if (confd == sig_pipefd[0] && (events[i].events & EPOLLIN))
                {
                    char signals[1024];
                    memset(signals, '\0', sizeof(signals));
                    int ret = recv(confd, signals, sizeof(signals), 0);
                    if (ret > 0)
                    {
                        for (int j = 0;j < ret;j++)
                        {
                            switch (signals[j])
                            {
                            case SIGCHLD:
                                pid_t pid;
                                int stat;
                                while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
                                {
                                    continue;
                                }
                                break;
                            case SIGINT:
                            case SIGTERM:
                                stop = true;
                                break;
                            default:
                                break;
                            }
                        }
                    }
                    else
                        continue;
                }
                //有数据到来
                else if (events[i].events & EPOLLIN)
                {
                    printf("有数据到来了\n");
                    users[confd].process();
                }
                else
                    continue;
            }
        }
        delete[] users;
        users = NULL;
        //close(listen_sock);  //哪个创建，就由哪个关闭
        close(epfd);
        close(pefd);
    }

    //统一事件源
    void sig_setup()
    {
        epfd = epoll_create(5);
        assert(epfd != -1);
        //创建管道
        int ret = socketpair(PF_UNIX, SOCK_STREAM, 0, sig_pipefd);
        assert(ret != -1);

        util::setNonBlock(sig_pipefd[1]);
        util::addEvent(epfd, sig_pipefd[0]);
        //添加信号
        util::addSig(SIGCHLD, util::sig_handler);
        util::addSig(SIGTERM, util::sig_handler);
        util::addSig(SIGINT, util::sig_handler);
        util::addSig(SIGPIPE, SIG_IGN);
    }
private:
    static processPool<T>* inst;
private:
    //最大进程数量
    static const int MAX_PROCESS_NUMBER = 16;
    //子进程最多能处理的连接个数
    static const int USER_PER_PROCESS = 65536;
    //内核事件数量
    static const int MAX_EVENT_NUMBER = 1024;
    //监听套接字
    int listen_sock;
    //epoll模型
    int epfd;
    //进程编号
    int idx;
    //当前进程数量
    int process_num;
    //子进程描述数组
    process* sub_process;
    //循环运行开关
    bool stop;
};
template <class T>
processPool<T>* processPool<T>::inst = nullptr;